package org.ethan.pay.service.impl;

import com.alibaba.fastjson.JSON;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.page.models.AlipayTradePagePayResponse;
import org.ethan.basic.exception.BasicException;
import org.ethan.order.domain.OrderPet;
import org.ethan.order.domain.OrderPetDetail;
import org.ethan.order.mapper.OrderPetDetailMapper;
import org.ethan.order.mapper.OrderPetMapper;
import org.ethan.pay.domain.PayAlipayInfo;
import org.ethan.pay.domain.PayBill;
import org.ethan.pay.domain.PayFlow;
import org.ethan.pay.dto.AlipayNotifyDto;
import org.ethan.pay.mapper.PayAlipayInfoMapper;
import org.ethan.pay.mapper.PayBillMapper;
import org.ethan.pay.mapper.PayFlowMapper;
import org.ethan.pay.service.IPayService;
import org.ethan.pet.domain.Pet;
import org.ethan.pet.mapper.PetMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class PayServiceImpl  implements IPayService {

    @Autowired
    private PayAlipayInfoMapper alipayInfoMapper;
    @Autowired
    private PayBillMapper payBillMapper ;
    @Autowired
    private PayFlowMapper payFlowMapper;
    @Autowired
    private OrderPetMapper orderPetMapper ;
    @Autowired
    private OrderPetDetailMapper orderPetDetailMapper;
    @Autowired
    private PetMapper petMapper;


    //支付申请
    @Override
    public String applyPay(String orderNum) {
        //1.判断参数
        if(StringUtils.isEmpty(orderNum)){
            throw new BasicException("非法请求");
        }

        //2.加载支付宝配置
        PayAlipayInfo alipayInfo = alipayInfoMapper.selectFirst();
        if(alipayInfo == null){
            throw new BasicException("非法支付宝配置");
        }

        //3.查询支付单
        PayBill payBill = payBillMapper.selectByNum(orderNum);
        if(payBill == null){
            throw new BasicException("非法请求");
        }
        //4.发起支付请求
        // 1. 设置参数（全局只需设置一次）
        Factory.setOptions(alipayInfo.getOptions());

        try {
            // 2. 发起API调用:电脑网站
            //String returnUrl = String.format("http://127.0.0.1/pay-success.html?orderNum=%s",orderNum);
            String returnUrl = String.format(alipayInfo.getReturnUrl(),orderNum);

            AlipayTradePagePayResponse response = Factory.Payment.Page()
                    .pay(payBill.getDigest(), // 标题
                         payBill.getUnionPaySn(), // 单号
                         payBill.getMoney().toString(), // 金额
                            returnUrl); // 同步回调地址

            // 3. 处理响应或异常
            if (ResponseChecker.success(response)) {
                System.out.println("调用成功");
                // 4.处理结果
                return response.body;
            } else {
                System.err.println("调用失败，原因：" );
            }

        } catch (Exception e) {
            System.err.println("调用遭遇异常，原因：" + e.getMessage());
            throw new RuntimeException(e.getMessage(), e);
        }

        return "支付申请失败";
    }

    /**
     * 支付结果处理
     * 1.校验参数
     * 2.验证签名
     * 3.防止支付结果重复处理 ,支付宝会回调N次
     *                      - 幂等性处理：调用N次和调用1次的结果一样
     * 3.保存支付流水PayFlow
     * 4.修改支付单状态PayBill
     * 5.修改业务单状态OrderPet
     * 6.如果是失败，宠物库存退回
     *
     * @param dto ：支付宝网关返回的参数
     */
    @Override
    public String alipayNotify(AlipayNotifyDto dto) {
        //* 1.校验参数
        //* 2.验证签名

        //把结果DTO转成HashMap用作签名参数
        //... ... 接收到的所有参数放入一个Map中
        //把对象转成JSON字符串
        String JSONStr = JSON.toJSONString(dto);
        //把JSON字符串转成Map
        Map<String, String> parameters = JSON.parseObject(JSONStr, Map.class);

        //支付宝的配置
        PayAlipayInfo alipayInfo = alipayInfoMapper.selectFirst();
        try {
            Boolean verifySignSuccess = Factory.Payment.Common().verifyNotify(parameters);
            if(!verifySignSuccess){
                System.out.println("验证签名失败...");
                return "fail";
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //判断结果
        //判断订单号，金额是否一致
        String out_trade_no = dto.getOut_trade_no();
        if(!StringUtils.hasLength(out_trade_no)){
            System.out.println("无效的单号...");
            return "fail";
        }
        PayBill payBill = payBillMapper.selectByNum(out_trade_no);
        if(payBill == null){
            System.out.println("无效的单号...");
            return "fail";
        }

        //* 3.防止支付结果重复处理 ,支付宝会回调N次
        //*                      - 幂等性处理：调用N次和调用1次的结果一样
        // 判断支付单是否被处理过，如果处理过了不要处理了，状态必须为：支付中
        if(payBill.getState().intValue() != PayBill.SATET_WAIT_PAY){
            //支付已经被处理
            System.out.println("订单号已经被处理...");
            return "success";
        }

        //对比金额
        BigDecimal amount = new BigDecimal(dto.getTotal_amount());
        if(payBill.getMoney().compareTo(amount) != 0){
            System.out.println("无效的金额...");
            return "fail";
        }


        String app_id = dto.getApp_id();
        if(!StringUtils.hasLength(app_id) || !app_id.equals(alipayInfo.getAppid())){
            System.out.println("无效的APPID...");
            return "fail";
        }

        //* 3.保存支付流水PayFlow
        PayFlow payFlow = new PayFlow();
        BeanUtils.copyProperties(dto, payFlow);
        payFlowMapper.add(payFlow);

        //* 4.修改支付单状态PayBill
        if(dto.isTradeWait()){
            System.out.println("支付中，不处理...");
            return "fail";
        }

        //业务单
        OrderPet orderPet = orderPetMapper.selectByOrderNum(out_trade_no);

        /*
        List<Long> petIds = new ArrayList<>(details.size());
        details.forEach(detail->{
            petIds.add(detail.getPetId());
        });
        */

        if(orderPet == null){
            System.out.println("无效的单号...");
            return "fail";
        }
        //订单明细
        List<OrderPetDetail> details =  orderPetDetailMapper.selectByOrderNum(out_trade_no);
        //JAVA 1.8新特性
        List<Long> petIds = details.stream().map(detail -> detail.getPetId()).collect(Collectors.toList());
        //查询所有宠物,这里查询的上线
        List<Pet> pets = petMapper.batchSelectByIds(petIds, Pet.STATE_ONSALE);

        //支付成功，失败，超时
        if(dto.isTradeSuccess()){
            //成功
            payBill.setState(PayBill.SATET_SUCCESS_PAY);
            //* 5.修改业务单状态OrderPet
            //支付成功，待发货
            orderPet.setState(OrderPet.STATE_SUCCESS_PAY);

        } else if (dto.isTradeExpire()){
            //超时
            payBill.setState(PayBill.SATET_OUTTIME_OR_RETURN);
            orderPet.setState(OrderPet.STATE_PAY_TIMEOUT_CANCEL);
            //* 6.如果是失败，宠物库存退回
            pets.forEach(pet -> {
                //严格来说应该加订单明细表中的count
                pet.setStorage_num(pet.getStorage_num() + 1);
                petMapper.update(pet);
            });
        } else {
            System.out.println("未知的交易状态");
            return "fail";
        }
        //最后支付处理时间
        payBill.setLastPayTime(new Date());
        payBillMapper.update(payBill);
        orderPetMapper.update(orderPet);

        return "success";
    }
}
